/***************************************************************************************
 The copyright in this software is being made available under the BSD License, included
 below. This software may be subject to other third party rights,including patent rights,
 and no such rights are granted under this license.

 Regents of the Tsinghua University, Peking University, Zhejiang University, HKUST
 Tsinghua University, Peking University, Zhejiang University, HKUST 2011

 Copyright (c) 2011, Regents of the Tsinghua University, Peking University, Zhejiang
 University, HKUST. All Rights Reserved.

 Redistribution and use in source and binary forms, with or without modification, are
 permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the names of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 OF SUCH DAMAGE.
***************************************************************************************/

#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include "contributors.h"
#include "global.h"
#include "macroblock.h"
#include "vlc.h"

#include "defines.h"
#include "block.h"

#include "qcoder.h"

const byte QP_SCALE_CR[64] =
{
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
    20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
    30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
    40, 41, 42, 42, 43, 43, 44, 44, 45, 45,
    46, 46, 47, 47, 48, 48, 48, 49, 49, 49,
    50, 50, 50, 51,
};

const byte NCBP[64][2] =
{
    {63, 0}, {15, 15}, {31, 63}, {47, 31}, {0, 16}, {14, 32}, {13, 47}, {11, 13}, {7, 14}, {5, 11},
    {10, 12}, {8, 5}, {12, 10}, {61, 7}, {4, 48}, {55, 3}, {1, 2}, {2, 8}, {59, 4}, {3, 1},
    {62, 61}, {9, 55}, {6, 59}, {29, 62}, {45, 29}, {51, 27}, {23, 23}, {39, 19}, {27, 30}, {46, 28},
    {53, 9}, {30, 6}, {43, 60}, {37, 21}, {60, 44}, {16, 26}, {21, 51}, {28, 35}, {19, 18}, {35, 20},
    {42, 24}, {26, 53}, {44, 17}, {32, 37}, {58, 39}, {24, 45}, {20, 58}, {17, 43}, {18, 42}, {48, 46},
    {22, 36}, {33, 33}, {25, 34}, {49, 40}, {40, 52}, {36, 49}, {34, 50}, {50, 56}, {52, 25}, {54, 22},
    {41, 54}, {56, 57}, {38, 41}, {57, 38},
};

const int BLOCK_STEP[8][2] =
{
    {0, 0}, {2, 2}, {2, 1}, {1, 2}, {1, 1}, {2, 1}, {1, 2}, {1, 1}
};

void read_chroma_intra_mode( image_t *img,input_t * inp, int *intramode );
void read_luma_intra_mode( image_t *img,input_t * inp, int *intramode );

void read_mv( image_t *img, input_t *inp );
extern void tracebits3( const char *trace_str, int len, int info, int value1 );

#define MODE_IS_P8x8  (mbmode==4)
#define MODE_IS_I4x4  (mbmode==5)
#define I16OFFSET     (mbmode-7)
/*
******************************************************************************
*  Function: calculated field or frame distance between current field(frame)
*            and the reference field(frame).
*     Input: blkref
fw_bw
*    Output: distance for motion vector scale
*    Return:
* Attention:
*    Author: Yulejun // 2004.07.14
******************************************************************************
*/
int calculate_distance( int blkref, int fw_bw ) //fw_bw>=0: forward ; fw_bw<0: backward
{
    int distance;
    if ( 1 /*img->picture_structure*/ == 1 )    //frame coding
    {
        if ( img->type == P_IMG )   // P img
        {
            if ( blkref == 0 )
                distance = picture_distance * 2 - img->imgtr_last_P * 2;
            else if ( blkref == 1 )
                distance = picture_distance * 2 - img->imgtr_last_prev_P * 2;
            else
            {
                assert( 0 );            //only two reference pictures for P frame
            }
        }
        else                        //B_IMG
        {
            if ( fw_bw >= 0 )         //forward
                distance = picture_distance * 2 - img->imgtr_last_P * 2;
            else
                distance = img->imgtr_next_P * 2 - picture_distance * 2;
        }
    }
    else if ( 0/*!img->picture_structure*/ )    //field coding
    {
        if ( img->type == P_IMG )
        {
            if ( img->top_bot == 0 )  //top field
            {
                switch ( blkref )
                {
                    case 0:
                        distance = picture_distance * 2 - img->imgtr_last_P * 2 - 1;
                        break;
                    case 1:
                        distance = picture_distance * 2 - img->imgtr_last_P * 2;
                        break;
                    case 2:
                        distance = picture_distance * 2 - img->imgtr_last_prev_P * 2 - 1;
                        break;
                    case 3:
                        distance = picture_distance * 2 - img->imgtr_last_prev_P * 2;
                        break;
                }
            }
            else if ( img->top_bot == 1 )     // bottom field.
            {
                switch ( blkref )
                {
                    case 0:
                        distance = 1;
                        break;
                    case 1:
                        distance = picture_distance * 2 - img->imgtr_last_P * 2;
                        break;
                    case 2:
                        distance = picture_distance * 2 - img->imgtr_last_P * 2 + 1;
                        break;
                    case 3:
                        distance = picture_distance * 2 - img->imgtr_last_prev_P * 2;
                        break;
                }
            }
            else
            {
                printf( "Error. frame picture should not run into this branch." );
                exit( -1 );
            }
        }
        else if ( img->type == B_IMG )
        {
            assert( blkref == 0 || blkref == 1 );
            if ( fw_bw >= 0 )         //forward
            {
                if ( img->top_bot == 0 ) //top field
                {
                    switch ( blkref )
                    {
                        case 0:
                            distance = picture_distance * 2 - img->imgtr_last_P * 2 - 1;
                            break;
                        case 1:
                            distance = picture_distance * 2 - img->imgtr_last_P * 2;
                            break;
                    }
                }
                else if ( img->top_bot == 1 )   // bottom field.
                {
                    switch ( blkref )
                    {
                        case 0:
                            distance = picture_distance * 2 - img->imgtr_last_P * 2;
                            break;
                        case 1:
                            distance = picture_distance * 2 - img->imgtr_last_P * 2 + 1;
                            break;
                    }
                }
                else
                {
                    printf( "Error. frame picture should not run into this branch." );
                    exit( -1 );
                }
            }
            else                      // backward
            {
                if ( img->top_bot == 0 ) //top field
                {
                    switch ( blkref )
                    {
                        case 0:
                            distance = img->imgtr_next_P * 2 - picture_distance * 2;
                            break;
                        case 1:
                            distance = img->imgtr_next_P * 2 - picture_distance * 2 + 1;
                            break;
                    }
                }
                else if ( img->top_bot == 1 )   // bottom field.
                {
                    switch ( blkref )
                    {
                        case 0:
                            distance = img->imgtr_next_P * 2 - picture_distance * 2 - 1;
                            break;
                        case 1:
                            distance = img->imgtr_next_P * 2 - picture_distance * 2;
                            break;
                    }
                }
                else
                {
                    printf( "Error. frame picture should not run into this branch." );
                    exit( -1 );
                }
            }

        }
    }
    distance = ( distance + 512 ) % 512;
    return distance;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int scale_motion_vector( int motion_vector, int currblkref, int neighbourblkref, int currsmbtype, int neighboursmbtype, int block_y_pos, int curr_block_y, int ref, int direct_mv )
{
    int sign = ( motion_vector > 0 ? 1 : -1 );
    int mult_distance;
    int devide_distance;

    motion_vector = abs( motion_vector );

    if ( motion_vector == 0 )
        return 0;

    mult_distance = calculate_distance( currblkref, ref );
    devide_distance = calculate_distance( neighbourblkref, ref );

    motion_vector = sign * ( ( motion_vector * mult_distance * ( 512 / devide_distance ) + 256 ) >> 9 );

    return motion_vector;
}


/*
*************************************************************************
* Function:Checks the availability of neighboring macroblocks of
the current macroblock for prediction and context determination;
marks the unavailable MBs for intra prediction in the
ipredmode-array by -1. Only neighboring MBs in the causal
past of the current MB are checked.
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

void CheckAvailabilityOfNeighbors( image_t *img )
{
    int i, j;
    const int mb_width = img->width / MB_BLOCK_SIZE;
    const int mb_nr = img->current_mb_nr;
    macroblock_t *currMB = &mb_data[mb_nr];
    int check_value;

    // mark all neighbors as unavailable
    for ( i = 0; i < 3; i++ )
        for ( j = 0; j < 3; j++ )
            mb_data[mb_nr].mb_available[i][j] = NULL;

    mb_data[mb_nr].mb_available[1][1] = currMB;   // current MB

    // Check MB to the left
    if ( img->pix_x >= MB_BLOCK_SIZE )
    {
        int remove_prediction = currMB->slice_nr != mb_data[mb_nr - 1].slice_nr;
        // upper blocks
        if ( remove_prediction )
        {
        }
        if ( !remove_prediction )
        {
            currMB->mb_available[1][0] = &( mb_data[mb_nr - 1] );
        }
    }
    // Check MB above
    check_value = ( img->pix_y >= MB_BLOCK_SIZE );
    if ( check_value )
    {
        int remove_prediction = currMB->slice_nr != mb_data[mb_nr - mb_width].slice_nr;
        // upper blocks
        if ( remove_prediction )
        {
        }

        if ( !remove_prediction )
        {
            currMB->mb_available[0][1] = &( mb_data[mb_nr - mb_width] );
        }
    }
    // Check MB left above
    if ( img->pix_y >= MB_BLOCK_SIZE && img->pix_x >= MB_BLOCK_SIZE )
    {
        int remove_prediction = currMB->slice_nr != mb_data[mb_nr - mb_width - 1].slice_nr;

        if ( remove_prediction )
        {
        }
        if ( !remove_prediction )
        {
            currMB->mb_available[0][0] = &( mb_data[mb_nr - mb_width - 1] );
        }
    }
    // Check MB right above
    if ( img->pix_y >= MB_BLOCK_SIZE && img->pix_x < ( img->width - MB_BLOCK_SIZE ) )
    {
        if ( currMB->slice_nr == mb_data[mb_nr - mb_width + 1].slice_nr )
            currMB->mb_available[0][2] = &( mb_data[mb_nr - mb_width + 1] );
    }

}

void set_MB_parameters( image_t *img, input_t *inp, int mb )
{
    const int number_mb_per_row = img->width / MB_BLOCK_SIZE;

    img->mb_x = mb % number_mb_per_row;
    img->mb_y = mb / number_mb_per_row;

    // Define vertical positions
    img->block8_y = img->mb_y * B4_SIZE / 2;
    img->block_y = img->mb_y * B4_SIZE / 2;    // vertical luma block position
    img->pix_y = img->mb_y * MB_BLOCK_SIZE;       // vertical luma macroblock position
    if ( chroma_format == 2 )
        img->pix_c_y = img->mb_y * MB_BLOCK_SIZE;   // vertical chroma macroblock position  //added by wuzhongmou 422
    else
        img->pix_c_y = img->mb_y * MB_BLOCK_SIZE / 2;       // vertical chroma macroblock position

    // Define horizontal positions
    img->block8_x = img->mb_x * B4_SIZE / 2;
    img->block_x = img->mb_x * B4_SIZE / 2;    // luma block
    img->pix_x = img->mb_x * MB_BLOCK_SIZE;       // luma pixel
    img->pix_c_x = img->mb_x * MB_BLOCK_SIZE / 2; // chroma pixel

}

/*
*************************************************************************
* Function:initializes the current macroblock
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

void start_macroblock( image_t *img, input_t *inp )
{
    int i, j, k, l;
    macroblock_t *currMB;

    assert( img->current_mb_nr >= 0 && img->current_mb_nr < img->max_mb_nr );

    currMB = &mb_data[img->current_mb_nr];

    /* Update coordinates of the current macroblock */
    img->mb_x = ( img->current_mb_nr ) % ( img->width / MB_BLOCK_SIZE );
    img->mb_y = ( img->current_mb_nr ) / ( img->width / MB_BLOCK_SIZE );

    /* Define vertical positions */
    img->block_y = img->mb_y * B4_SIZE / 2;    /* luma block position */
    img->block8_y = img->mb_y * B4_SIZE / 2;
    img->pix_y = img->mb_y * MB_BLOCK_SIZE;       /* luma macroblock position */
    if ( chroma_format == 2 )
        img->pix_c_y = img->mb_y * MB_BLOCK_SIZE;   /* chroma macroblock position *///added by wuzhongmou 422
    else
        img->pix_c_y = img->mb_y * MB_BLOCK_SIZE / 2;       /* chroma macroblock position */

    /* Define horizontal positions */
    img->block_x = img->mb_x * B4_SIZE / 2;    /* luma block position */
    img->block8_x = img->mb_x * B4_SIZE / 2;
    img->pix_x = img->mb_x * MB_BLOCK_SIZE;       /* luma pixel position */
    img->pix_c_x = img->mb_x * MB_BLOCK_SIZE / 2; /* chroma pixel position */

    // If MB is next to a slice boundary, mark neighboring blocks unavailable for prediction
    CheckAvailabilityOfNeighbors( img );  // support only slice mode 0 in MBINTLC1 at this time

    // Reset syntax element entries in MB struct
    currMB->qp = img->qp;
    currMB->qp_16x16 = img->qp;

    currMB->qp_4x4 = img->qp;
    currMB->mb_type = 0;
    currMB->delta_quant = 0;
    currMB->cbp = 0;
    currMB->cbp_blk = 0;
    currMB->transform_16x16 = 0;
    currMB->cbp_16x16 = 0;
    for ( i=0; i<4; i++ )
    {
        currMB->transform_4x4[i] = 0;
        currMB->cbp_4x4[i] = 0;
    }

    for ( l = 0; l < 2; l++ )
        for ( j = 0; j < 2; j++ )
            for ( i = 0; i < 2; i++ )
                for ( k = 0; k < 2; k++ )
                    currMB->mvd[l][j][i][k] = 0;

    currMB->cbp_bits = 0;

    // initialize img->m7 for ABT
    for ( j = 0; j < MB_BLOCK_SIZE; j++ )
        for ( i = 0; i < MB_BLOCK_SIZE; i++ )
            img->m7[i][j] = 0;

    for ( j = 0; j < 2 * B4_SIZE; j++ ) //422
        for ( i = 0; i < 2 * B4_SIZE; i++ )
        {
            img->m8[0][i][j] = 0;
            img->m8[1][i][j] = 0;
            img->m8[2][i][j] = 0;
            img->m8[3][i][j] = 0;
        }

    img->weighting_prediction = 0;
}


/*
*************************************************************************
* Function:Interpret the mb mode for B-Frames
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
//int value2mbtype[24][5]={
//  { SKIP,       BI, BI, BI, BI},
//  {INTER16x16,  BI, BI, BI, BI},
//  {INTER16x8,   BW, BW, BI, BI},
//  {INTER8x16,   BW, BI, BW, BI},
//  {INTER16x8,   BI, BI, BW, BW},
//  {INTER8x16,   BI, BW, BI, BW},
//  {INTER16x8,   FW, FW, BI, BI},
//  {INTER8x16,   FW, BI, FW, BI},
//  {INTER16x8,   BI, BI, FW, FW},
//  {INTER8x16,   BI, FW, BI, FW},
//  {INTER16x16,  BW, BW, BW, BW},
//  {INTER16x8,   BW, BW, BW, BW},
//  {INTER8x16,   BW, BW, BW, BW},
//  {INTER16x8,   FW, FW, BW, BW},
//  {INTER8x16,   FW, BW, FW, BW},
//  {INTER16x8,   BW, BW, FW, FW},
//  {INTER8x16,   BW, FW, BW, FW},
//  {INTER16x16,  FW, FW, FW, FW},
//  {INTER16x8,   FW, FW, FW, FW},
//  {INTER8x16,   FW, FW, FW, FW},
//  {INTER16x8,   BI, BI, BI, BI},
//  {INTER8x16,   BI, BI, BI, BI},
//  {INTER8x8,    -1, -1, -1, -1},
//  {I8MB,        0, 0, 0, 0},
//};
////int value2mbtype[24][5]={
//  { SKIP,       BI, BI, BI, BI},
//  {INTER16x16,  BI, BI, BI, BI},
//  {INTER16x8,   FW, FW, BI, BI},
//  {INTER8x16,   FW, BI, FW, BI},
//  {INTER16x8,   BI, BI, FW, FW},
//  {INTER8x16,   BI, FW, BI, FW},
//  {INTER16x8,   BW, BW, BI, BI},
//  {INTER8x16,   BW, BI, BW, BI},
//  {INTER16x8,   BI, BI, BW, BW},
//  {INTER8x16,   BI, BW, BI, BW},
//  {INTER16x16,  FW, FW, FW, FW},
//  {INTER16x8,   FW, FW, FW, FW},
//  {INTER8x16,   FW, FW, FW, FW},
//  {INTER16x8,   BW, BW, FW, FW},
//  {INTER8x16,   BW, FW, BW, FW},
//  {INTER16x8,   FW, FW, BW, BW},
//  {INTER8x16,   BW, BW, FW, FW},
//  {INTER16x16,  BW, BW, BW, BW},
//  {INTER16x8,   BW, BW, BW, BW},
//  {INTER8x16,   BW, BW, BW, BW},
//  {INTER16x8,   BI, BI, BI, BI},
//  {INTER8x16,   BI, BI, BI, BI},
//  {INTER8x8,    -1, -1, -1, -1},
//  {I8MB,        -1, -1, -1, -1},
//};

static void set_b_mv( mv_t* mv, bi_mv_t bi_mv, int dir )
{
    if ( dir == FW )
    {
        if ( bi_mv.fw_mv.ref != -1 )
        {
            *mv = bi_mv.fw_mv;
        }
        else
        {
            mv->ref = 0;
            mv->x = 0;
            mv->y = 0;
        }
    }
    else //bw
    {
        if ( bi_mv.bw_mv.ref != -1 )
        {
            *mv = bi_mv.bw_mv;
        }
        else
        {
            mv->ref = 1;
            mv->x = 0;
            mv->y = 0;

        }
    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

static void get_pred_mv_p( mv_t *pred_mv, int ref_idx, int mb_pix_x, int mb_pix_y, int mode )
{
    mv_t mva, empty_mv= {0, 0, -1};
    int  mb_available_left ;
    int  block_available_left;
    int pic_block_x = img->block8_x + ( mb_pix_x>>3 );
    int pic_block_y = img->block8_y + ( mb_pix_y>>3 );
    macroblock_t* currMB, *leftMB;

    pred_mv = ( mv_t* ) pred_mv;
    currMB  = &mb_data[img->current_mb_nr];
    if ( img->current_mb_nr >= 1 )
    {
        leftMB = &mb_data[img->current_mb_nr - 1];
        mb_available_left = ( img->mb_x == 0 ) ? 0 : ( currMB->slice_nr == leftMB->slice_nr );
    }
    else
    {
        leftMB = NULL;
        mb_available_left = 0;
    }

    block_available_left = mb_available_left || ( mb_pix_x > 0 );

    if ( block_available_left )
    {
        //add the probable conditions
        if( mb_pix_x == 0 ) //use the left mb's mv
        {
            switch ( leftMB->mb_type )
            {
                case SKIP:
                    mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-2];
                    break;

                case INTER16x16:
                    mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-2];
                    break;

                case INTER8x8:
                    switch ( leftMB->subblock_type[2*( mb_pix_y/8 )+1] )
                    {
                        case SUBBLOCK_INTER8x8:
                            mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-1];
                            break;

                        case SUBBLOCK_INTER4x4:
                            mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][img->block8_x-1][( mb_pix_y%8 )/4][1];
                            break;

                        default:
                            mva = empty_mv;
                    }

                    break;

                default: //???how to calculate skip mode
                    mva = empty_mv;
            }
        }
        else
        {
            switch ( mode )
            {
                case INTER8x8:
                    if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 ) //left block
                        mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-1];
                    else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                        mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1];
                    else
                        mva = empty_mv;
                    break;

                case INTER4x4:
                    if( mb_pix_x!=8 )
                        mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][pic_block_x][( mb_pix_y%8 )/4][0];
                    else
                    {
                        if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 )
                            mva = frm_mv[MAX_REF_NUM][pic_block_y][pic_block_x-1];
                        else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                            mva = frm_mv_4x4[MAX_REF_NUM][pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1];
                        else
                            mva = empty_mv;
                    }
                    break;

                default:
                    mva = empty_mv;
            }
        }
    }
    else
    {
        mva = empty_mv;
    }

    *pred_mv = mva;
    pred_mv->ref = ref_idx;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void get_pred_mv_b( mv_t *pred_mv, int ref_idx, int mb_pix_x, int mb_pix_y, int mode )
{
    mv_t mva, empty_mv= {0, 0, -1};
    int  mb_available_left ;
    int  block_available_left;
    int pic_block_x = img->block8_x + ( mb_pix_x>>3 );
    int pic_block_y = img->block8_y + ( mb_pix_y>>3 );
    macroblock_t* currMB, * leftMB;

    pred_mv = ( mv_t* )pred_mv;
    currMB  = &mb_data[img->current_mb_nr];
    if ( img->current_mb_nr >= 1 )
    {
        leftMB = &mb_data[img->current_mb_nr - 1];
        mb_available_left = ( img->mb_x == 0 ) ? 0 : ( currMB->slice_nr == leftMB->slice_nr );
    }
    else
    {
        leftMB = NULL;
        mb_available_left = 0;
    }


    block_available_left = mb_available_left || ( mb_pix_x > 0 );

    if ( block_available_left )
    {
        //add the probable conditions
        if( mb_pix_x == 0 ) //use the left mb's mv
        {
            switch ( leftMB->mb_type )
            {
                case SKIP:
                    set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-2], ref_idx );
                    break;

                case INTER16x16:
                    set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-2], ref_idx );
                    break;

                case INTER8x8:
                    switch ( leftMB->subblock_type[2*( mb_pix_y/8 )+1] )
                    {
                        case SUBBLOCK_INTER8x8:
                            set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-1], ref_idx );
                            break;

                        case SUBBLOCK_INTER4x4:
                            set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][img->block8_x-1][( mb_pix_y%8 )/4][1], ref_idx );
                            break;

                        default:
                            mva = empty_mv;
                    }
                    break;

                default: //???how to calculate skip mode
                    mva = empty_mv;
            }
        }

        else
        {
            switch ( mode )
            {
                case SUBBLOCK_INTER8x8:
                    if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 ) //left block
                        set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-1], ref_idx );
                    else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                        set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1], ref_idx );
                    else
                        mva = empty_mv;
                    break;

                case SUBBLOCK_INTER4x4:
                    if( mb_pix_x!=8 )
                        set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][pic_block_x][( mb_pix_y%8 )/4][0], ref_idx );
                    else
                    {
                        if( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER8x8 )
                            set_b_mv( &mva, frm_bi_mv[pic_block_y][pic_block_x-1], ref_idx );
                        else if ( currMB->subblock_type[2*( mb_pix_y/8 )] == SUBBLOCK_INTER4x4 )
                            set_b_mv( &mva, frm_bi_mv_4x4[pic_block_y][pic_block_x-1][( mb_pix_y%8 )/4][1], ref_idx );
                        else
                            mva = empty_mv;
                    }
                    break;

                default:
                    mva = empty_mv;
            }
        }
    }
    else
    {
        mva = empty_mv;
    }

    *pred_mv = mva;
    pred_mv->ref = ref_idx;
}




void read_dqp( image_t *img, input_t *inp )
{
    macroblock_t *currMB = &mb_data[img->current_mb_nr];
    int fixqp;
    fixqp = ( fixed_picture_qp || fixed_slice_qp );
    if ( !fixqp && ( currMB->cbp ) ) //wzm,422
    {
        currMB->delta_quant = qcoder_decode_delta_qp( qcoder );
        if ( img->qp+currMB->delta_quant > 63 || img->qp+currMB->delta_quant < 0 )
        {
            CSyntax = 0;
#if SYNTAX_REPORT
            fprintf( p_sreport,"error(0)               (%3d|%3d) @ MB%d\n",currMB->delta_quant,img->qp+currMB->delta_quant,1 /*img->picture_structure*/==0
                     ?img->current_mb_nr_fld:img->current_mb_nr );
#endif
        }
        img->qp = ( img->qp - MIN_QP + currMB->delta_quant + ( MAX_QP - MIN_QP + 1 ) ) % ( MAX_QP - MIN_QP + 1 ) + MIN_QP; //discussed by cjw Zhuhai 20070123
    }
    if ( fixqp )
    {
        currMB->delta_quant = 0;
        img->qp = ( img->qp - MIN_QP + currMB->delta_quant + ( MAX_QP - MIN_QP + 1 ) ) % ( MAX_QP - MIN_QP + 1 ) + MIN_QP;
    }
}

/*
*************************************************************************
* Function:read one macroblock
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void read_one_macroblock( image_t *img, input_t *inp )
{
    //int block8x8, blk4x4;
    int block8x8,block4x4,i,j,k,m;
    mv_t intra_mv= {0,0,-1};
    mv_t tmp_mv;

    macroblock_t *currMB = &mb_data[img->current_mb_nr];

    int tempintramode=0;
    int pred_direction;;
    currMB->qp = img->qp;

    for ( block8x8 = 0; block8x8 < 8; block8x8++ )
        for ( block4x4 = 0; block4x4 < 8; block4x4++ )
        {
            img->m8[0][block8x8][block4x4] = 0;
            img->m8[1][block8x8][block4x4] = 0;
            img->m8[2][block8x8][block4x4] = 0;
            img->m8[3][block8x8][block4x4] = 0;
        }

    currMB->qp = img->qp;

    for( block8x8 =0; block8x8<4; block8x8++ )
    {
        currMB->b8mode[block8x8/2][block8x8%2]=INTRA_NO;
        currMB->y_dc[block8x8/2][block8x8%2]=0;
        for ( k=0; k<2; k++ )
            for ( m=0; m<2; m++ )
            {
                currMB->b4mode[block8x8/2][block8x8%2][k][m] = INTRA_NO;
                currMB->y_4x4_dc[block8x8/2][block8x8%2][k][m] = 0;
            }
    }

    currMB->uvmode=INTRA_NO;
    currMB->uv_dc[0]=0;
    currMB->uv_dc[1]=0;
    currMB->b16mode = INTRA_NO;
    currMB->y_16x16_dc = 0;
    currMB->blocksize = 8;
    currMB->blocksize = qcoder_decode_blocksize( qcoder ) == 0? 8: 16;

    if( currMB->blocksize == 16 )
    {
        pred_direction = qcoder_decode_pred_direction( qcoder );
        if ( pred_direction != INTRA )
        {
            currMB->b8_ref[0][0] = currMB->b8_ref[1][0] = currMB->b8_ref[0][1] = currMB->b8_ref[1][1] = pred_direction;
            for ( block4x4=0; block4x4<2; block4x4++ )
                for ( block8x8=0; block8x8<2; block8x8++ )
                {
                    frm_mv[MAX_REF_NUM][img->block8_y+block4x4][img->block8_x+block8x8].ref = pred_direction;
                }

            currMB->mb_type = INTER16x16;
#if INTRA_MODE_ADAPTIVE
            for( block8x8=0; block8x8<4; block8x8++ )
                currMB->subblock_type[block8x8] = 0;//??initialize//xy_1107031
#else
			for( block8x8=0; block8x8<4; block8x8++ )
				currMB->subblock_type[block8x8] = 100;//not sure to determine the mode
#endif

            if( img->type==P_IMG )
            {
                get_pred_mv_p( &tmp_mv, frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x].ref, 0,0, INTER16x16 );

                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                tmp_mv.x += qcoder_decode_mvdx_num( qcoder, NUM_MVD_CX_16x16_QCODER );
                tmp_mv.y += qcoder_decode_mvdy_num( qcoder, NUM_MVD_CX_16x16_QCODER );

                tmp_mv.ref=frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x].ref;
                frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x]=
                    frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x+1]=
                        frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x]=
                            frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x+1]=tmp_mv;
            }
            else
            {
                switch( currMB->b8_ref[0][0] )
                {
                    case FW:
                        get_pred_mv_b( &tmp_mv,FW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=tmp_mv;
                        frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=intra_mv;
                        break;
                    case BW:
                        get_pred_mv_b( &tmp_mv,BW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=tmp_mv;
                        frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=intra_mv;
                        break;
                    case BI:
                        get_pred_mv_b( &tmp_mv,FW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=tmp_mv;

                        get_pred_mv_b( &tmp_mv,BW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=tmp_mv;
                        break;
                }
            }
            for( block8x8=0; block8x8<4; block8x8++ )
            {
                read_luma_coeff_b8_qcoder( block8x8, inp, img );
            }
        }
        else//if blocksize == 16,it must be inter mode or 4xI8
        {
            currMB->mb_type = I8MB;
            currMB->blocksize = 8;

            for( block8x8=0; block8x8<4; block8x8++ )
            {
                if ( vbs_enable )
                {
                    currMB->subblocksize[block8x8] = qcoder_decode_subblocksize( qcoder ) == 0? 8: 4;
                }
                else
                {
                    currMB->subblocksize[block8x8] = 8;
                }
                if ( currMB->subblocksize[block8x8] == 8 )
                {
                    currMB->transform_4x4[block8x8] = 0;
                    currMB->subblock_type[block8x8] = SUBBLOCK_INTRA8x8;
#if INTRA_MODE_ADAPTIVE
                    read_luma_intra_mode( img, inp, &tempintramode );
#endif
                    currMB->b8mode[block8x8/2][block8x8%2]=tempintramode;
                    read_luma_coeff_b8_qcoder( block8x8, inp, img );
                }
                else
                {
                    currMB->transform_4x4[block8x8] = 1;
                    currMB->subblock_type[block8x8] = SUBBLOCK_INTRA4x4;
                    for( block4x4=0; block4x4<4; block4x4++ )
                    {
                        currMB->b4_ref[block8x8][block4x4]=INTRA;
#if INTRA_MODE_ADAPTIVE
                        read_luma_intra_mode( img, inp, &tempintramode );
#endif
                        currMB->b4mode[block8x8/2][block8x8%2][block4x4/2][block4x4%2]=tempintramode;
                        read_luma_coeff_b4_qcoder( block8x8,block4x4, inp, img );
                    }
                }
            }
#if INTRA_MODE_ADAPTIVE_CHROMA
            read_chroma_intra_mode( img, inp, &tempintramode );
#endif
            currMB->uvmode = tempintramode;
        }
    }
    else
    {
        for( block8x8=0; block8x8<4; block8x8++ )
        {
            j = block8x8/2;
            i = block8x8%2;
            if ( vbs_enable )
            {
                currMB->subblocksize[block8x8] = qcoder_decode_subblocksize( qcoder ) == 0? 8: 4;
            }
            else
            {
                currMB->subblocksize[block8x8] = 8;
            }

            if ( currMB->subblocksize[block8x8] == 8 )
            {
                pred_direction = qcoder_decode_pred_direction( qcoder );
                if ( pred_direction != INTRA )
                {
                    currMB->b8_ref[block8x8/2][block8x8%2] = pred_direction;
                    currMB->mb_type = INTER8x8;
                    currMB->subblock_type[block8x8] = SUBBLOCK_INTER8x8;
                    currMB->transform_4x4[block8x8] = 0;
                    if ( img->type == I_IMG )
                        img->is_discard_frame =1;

                    if( img->type==P_IMG )
                    {
                        get_pred_mv_p( &tmp_mv, frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].ref, i*8, j*8, INTER8x8 );
#if TRACE
                        if ( 1 )
                        {
                            if ( p_trace )
                            {

                                fprintf( p_trace, "tmp_mv_x  is: %i ,tmp_mv_y  is: %i \n\n", tmp_mv.x, tmp_mv.y );
                            }
                        }
#endif
                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                        tmp_mv.ref=frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].ref;
                        frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i]=tmp_mv;

#if TRACE
                        if ( 1 )
                        {
                            if ( p_trace )
                            {

                                fprintf( p_trace, "frm_mv:x,y  is: %i,%i \n\n", tmp_mv.x,tmp_mv.y );
                            }
                        }
#endif
                    }
                    else
                    {
                        switch( currMB->b8_ref[j][i] )
                        {
                            case FW:
                                get_pred_mv_b( &tmp_mv,FW,i*8,j*8,INTER8x8 );
                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv=tmp_mv;
                                frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv=intra_mv;
#if TRACE
                                if ( 1 )
                                {
                                    if ( p_trace )
                                    {

                                        fprintf( p_trace, "FW  tmp_mv_x  is: %i ,tmp_mv_y  is: %i \n\n", tmp_mv.x, tmp_mv.y );
                                    }
                                }
#endif
                                break;
                            case BW:
                                get_pred_mv_b( &tmp_mv,BW,i*8,j*8,INTER8x8 );

                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv=tmp_mv;
                                frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv=intra_mv;
#if TRACE
                                if ( 1 )
                                {
                                    if ( p_trace )
                                    {

                                        fprintf( p_trace, "BW  tmp_mv_x  is: %i ,tmp_mv_y  is: %i \n\n", tmp_mv.x, tmp_mv.y );
                                    }
                                }
#endif

                                break;
                            case BI:
                                get_pred_mv_b( &tmp_mv,FW,i*8,j*8,INTER8x8 );
                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv=tmp_mv;

                                get_pred_mv_b( &tmp_mv,BW,i*8,j*8,INTER8x8 );

                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv=tmp_mv;
                                break;
                        }
                    }
                }
                else //8x8 intra
                {
                    currMB->mb_type = INTER8x8;
                    currMB->transform_4x4[block8x8] = 0;
                    currMB->subblock_type[block8x8] = SUBBLOCK_INTRA8x8;
#if INTRA_MODE_ADAPTIVE
                    read_luma_intra_mode( img, inp, &tempintramode );
#endif
                    currMB->b8mode[block8x8/2][block8x8%2]=tempintramode;
                    currMB->b8_ref[block8x8/2][block8x8%2] = BI;// add by xy_110911
                    frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i]=intra_mv;
                    frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv = intra_mv;
                    frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv = intra_mv;
                }
                read_luma_coeff_b8_qcoder( block8x8, inp, img );
            }
            else
            {
                for( block4x4=0; block4x4<4; block4x4++ )
                {
                    pred_direction = qcoder_decode_pred_direction( qcoder );
                    if( pred_direction != INTRA )
                    {
                        currMB->b4_ref[block8x8][block4x4] = pred_direction;
                        k = block4x4/2;
                        m = block4x4%2;
                        if( img->type==P_IMG )
                        {
                            get_pred_mv_p( &tmp_mv, frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].ref,  8*i+m*4, 8*j+k*4, INTER4x4 );
#if TRACE
                            if ( 1 )
                            {
                                if ( p_trace )
                                {

                                    fprintf( p_trace, "tmp_mv:x,y of inter4x4 is: %i,%i \n\n", tmp_mv.x,tmp_mv.y );
                                }
                            }
#endif

                            //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                            //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                            tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                            tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );

                            tmp_mv.ref=frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].ref;
                            frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m]=tmp_mv;

#if TRACE
                            if ( 1 )
                            {
                                if ( p_trace )
                                {

                                    fprintf( p_trace, "frm_mv:x,y of inter4x4 is: %i,%i \n\n", tmp_mv.x,tmp_mv.y );
                                }
                            }
#endif
                        }
                        else
                        {

                            switch( currMB->b4_ref[block8x8][block4x4] )
                            {
                                case FW:
                                    get_pred_mv_b( &tmp_mv,FW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );

                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv=tmp_mv;
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv=intra_mv;
                                    break;

                                case BW:
                                    get_pred_mv_b( &tmp_mv,BW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );

                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv=intra_mv;
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv=tmp_mv;
                                    break;

                                case BI:
                                    get_pred_mv_b( &tmp_mv,FW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv=tmp_mv;

                                    get_pred_mv_b( &tmp_mv,BW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv=tmp_mv;
                                    break;
                            }
                        }
                    }
                    else
                    {
                        currMB->mb_type = INTER8x8;
                        currMB->b4_ref[block8x8][block4x4] = pred_direction;
#if INTRA_MODE_ADAPTIVE
                        read_luma_intra_mode( img, inp, &tempintramode );
#endif
                        currMB->b4mode[block8x8/2][block8x8%2][block4x4/2][block4x4%2]=tempintramode;
                    }
                    read_luma_coeff_b4_qcoder( block8x8,block4x4, inp, img );
                }
                if ( currMB->b4_ref[block8x8][0] != INTRA )
                {
                    currMB->mb_type = INTER8x8;
                    currMB->subblock_type[block8x8] = SUBBLOCK_INTER4x4;
                    currMB->transform_4x4[block8x8] = 1;
                    currMB->b8_ref[block8x8/2][block8x8%2] = BI;
                    if ( img->type == I_IMG )
                        img->is_discard_frame =1;
                }
                else
                {
                    currMB->mb_type = INTER8x8;
                    currMB->transform_4x4[block8x8] = 1;
                    currMB->subblock_type[block8x8] = SUBBLOCK_INTRA4x4;
                    for( block4x4=0; block4x4<4; block4x4++ )
                        currMB->b4_ref[block8x8][block4x4] = BI;//xy_110913

                }
            }
        }
    }

    if( img->type==P_IMG )
    {
        if( currMB->mb_type == INTER8x8 )
        {
            for ( j=0; j<2; j++ )
                for ( i=0; i<2; i++ )
                {
                    block8x8 = 2*j+i;
                    if( currMB->subblock_type[block8x8] == SUBBLOCK_INTER4x4 )
                    {
                        for( block4x4=0; block4x4<4; block4x4++ )
                        {
                            frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][block4x4/2][block4x4%2].ref=FW;
                            currMB->b4_ref[block8x8][block4x4] = FW;
                        }
                    }
                    else
                    {
                        frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].ref=FW;
                        currMB->b8_ref[j][i] = frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].ref;
                    }
                }

        }
    }

    read_chroma_coeff_b8_qcoder( 4, inp, img );
    read_chroma_coeff_b8_qcoder( 5, inp, img );

    return;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void get_skipped_macroblock( image_t *img )
{
    macroblock_t *currMB = &mb_data[img->current_mb_nr];
    int i, j, iii, jjj;
    int dir;
    mv_t tmp_mv ;
    mv_t intra_mv = {0,0,-1};
    //int mb_available_up = (img->mb_y == 0) ? 0 : (currMB->slice_nr == mb_data[img->current_mb_nr - img->width / 16].slice_nr);
    //int mb_available_left = (img->mb_x == 0) ? 0 : (currMB->slice_nr == mb_data[img->current_mb_nr - 1].slice_nr);
    currMB->cbp = 0;

    currMB->mb_type = SKIP;
    for ( i =0; i<4; i++ )
        currMB->subblock_type[i] = 0;

    if ( img->type == I_IMG )
        img->is_discard_frame =1;

    for ( i = 0; i < B4_SIZE; i++ )
    {
        for ( j = 0; j < B4_SIZE; j++ )
            for ( iii = 0; iii < B4_SIZE; iii++ )
                for ( jjj = 0; jjj < B4_SIZE; jjj++ )
                    img->cof[i][j][iii][jjj] = 0;
    }
    for ( j = 4; j < 6; j++ )    //422
    {
        for ( i = 0; i < 4; i++ )
            for ( iii = 0; iii < 4; iii++ )
                for ( jjj = 0; jjj < 4; jjj++ )
                    img->cof[i][j][iii][jjj] = 0;
    }

    if( img->block8_x )
    {
        if( img->type==P_IMG )
        {
            get_pred_mv_p( &tmp_mv, 0, 0, 0, SKIP );
            frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x]=
                frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x]=
                    frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x+1]=
                        frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x+1]=tmp_mv;
            memset( currMB->b8_ref,0,2*2*sizeof( int ) );
        }
        else if ( img->type==B_IMG )
        {
#define GET_MV                                                                             \
  switch(dir)                                                                              \
      {                                                                                        \
  case FW:                                                                                 \
  get_pred_mv_b(&frm_bi_mv[img->block8_y][img->block8_x].fw_mv, FW, 0, 0, SKIP);  \
  frm_bi_mv[img->block8_y][img->block8_x].bw_mv = intra_mv;                              \
  break;                                                                                 \
            case BW:                                                                                 \
            get_pred_mv_b(&frm_bi_mv[img->block8_y][img->block8_x].bw_mv, BW, 0, 0, SKIP);  \
            frm_bi_mv[img->block8_y][img->block8_x].fw_mv = intra_mv;                              \
            break;                                                                                 \
            case BI:                                                                                 \
            get_pred_mv_b(&frm_bi_mv[img->block8_y][img->block8_x].fw_mv, FW, 0, 0, SKIP);  \
            get_pred_mv_b(&frm_bi_mv[img->block8_y][img->block8_x].bw_mv, BW, 0, 0, SKIP);  \
            break;                                                                                 \
    }

            //__________________________________________________________________________________________________________________________//
            if ( !img->pix_x )
            {
                //the direction is bi direction
                //get_pred_mv_b(&img->bi_mv[SKIP][j][i], 0, 0, 0, MB_BLOCK_SIZE, MB_BLOCK_SIZE);
                dir = BI;

                tmp_mv.x=tmp_mv.y=0;
                tmp_mv.ref=FW;
                frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                    frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                        frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                            frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=tmp_mv;

                tmp_mv.x=tmp_mv.y=0;
                tmp_mv.ref=BW;
                frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                    frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                        frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                            frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=tmp_mv;

            }
            else
            {
                //the direction is the same as the left block
                if( vbs_enable )
                    //dir = (mb_data[img->current_mb_nr-1].mb_type==INTER4x4 ? mb_data[img->current_mb_nr-1].b4_ref[1][1]:mb_data[img->current_mb_nr-1].b8_ref[0][1]);
                    dir = ( mb_data[img->current_mb_nr-1].subblock_type[1] == SUBBLOCK_INTER4x4 || mb_data[img->current_mb_nr-1].subblock_type[1] == SUBBLOCK_INTRA4x4 ) ? mb_data[img->current_mb_nr-1].b4_ref[1][1]: mb_data[img->current_mb_nr-1].b8_ref[0][1]; //xy_110506
                else
                    dir = mb_data[img->current_mb_nr-1].b8_ref[0][1];

                GET_MV;
            }

            frm_bi_mv[img->block8_y][img->block8_x+1] = frm_bi_mv[img->block8_y][img->block8_x] ;
            \
            frm_bi_mv[img->block8_y+1][img->block8_x] = frm_bi_mv[img->block8_y][img->block8_x] ;
            \
            frm_bi_mv[img->block8_y+1][img->block8_x+1] = frm_bi_mv[img->block8_y][img->block8_x] ;//xuyan


#if TRACE
            if ( 1 )
            {
                if ( p_trace )
                {
                    fprintf( p_trace, "B skip mode ref of currMB is: %i \n\n", dir );
                }
            }
#endif

            for ( j=0; j<2; j++ )
            {
                for ( i=0; i<2; i++ )
                {
                    currMB->b8_ref[j][i] = dir;
                }
            }
        }
    }
    else
    {
        if( img->type==P_IMG )
        {
            tmp_mv.x=tmp_mv.y=0;
            tmp_mv.ref=0;
            frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x]=
                frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x]=
                    frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x+1]=
                        frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x+1]=tmp_mv;
            memset( currMB->b8_ref,0,2*2*sizeof( int ) );
        }
        else if( img->type==B_IMG )
        {
            tmp_mv.x=tmp_mv.y=0;
            tmp_mv.ref=FW;
            frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                    frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                        frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=tmp_mv;

            tmp_mv.x=tmp_mv.y=0;
            tmp_mv.ref=BW;
            frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                    frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                        frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=tmp_mv;
            for ( j=0; j<2; j++ )
            {
                for ( i=0; i<2; i++ )
                {
                    currMB->b8_ref[j][i] = BI;
                }
            }

        }
    }
    return;
}




/*
*************************************************************************
* Function:Set context for reference frames
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

int BType2CtxRef( int btype )
{
    if ( btype < 4 )
        return 0;
    else
        return 1;
}

void read_luma_intra_mode( image_t *img,input_t * inp, int *intramode )
{

    *intramode = qcoder_decode_intra_luma_mode( qcoder );
}

void read_chroma_intra_mode( image_t *img,input_t * inp,int *intramode )
{

    *intramode = qcoder_decode_intra_chroma_mode( qcoder );
}


/*
*************************************************************************
* Function:Get coded block pattern and coefficients (run/level)
from the bitstream
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void read_mv( image_t *img, input_t *inp )
{
    macroblock_t *currMB = &mb_data[img->current_mb_nr];
    mv_t intra_mv= {0,0,-1};
    int k,m;
    int block8x8;
    mv_t tmp_mv;
    if( img->type==P_IMG )
    {
        switch( currMB->mb_type )
        {
            case INTER16x16:
                get_pred_mv_p( &tmp_mv, frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x].ref, 0,0, INTER16x16 );

                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                tmp_mv.ref=frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x].ref;
                frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x]=
                    frm_mv[MAX_REF_NUM][img->block8_y][img->block8_x+1]=
                        frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x]=
                            frm_mv[MAX_REF_NUM][img->block8_y+1][img->block8_x+1]=tmp_mv;
                break;
            case INTER8x8:
                for( block8x8=0; block8x8<4; block8x8++ )
                {
                    int j = block8x8/2;
                    int i = block8x8%2;
                    if ( currMB->subblock_type[block8x8]== SUBBLOCK_INTER8x8 )
                    {
                        get_pred_mv_p( &tmp_mv, frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].ref, i*8, j*8, INTER8x8 );
#if TRACE
                        if ( 1 )
                        {
                            if ( p_trace )
                            {

                                fprintf( p_trace, "tmp_mv_x  is: %i ,tmp_mv_y  is: %i \n\n", tmp_mv.x, tmp_mv.y );
                            }
                        }
#endif
                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                        tmp_mv.ref=frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].ref;
                        frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i]=tmp_mv;

#if TRACE
                        if ( 1 )
                        {
                            if ( p_trace )
                            {

                                fprintf( p_trace, "frm_mv:x,y  is: %i,%i \n\n", tmp_mv.x,tmp_mv.y );
                            }
                        }
#endif


                    }
                    else if( currMB->subblock_type[block8x8]== SUBBLOCK_INTER4x4 )
                    {
                        for ( k=0; k<2; k++ )
                            for ( m=0; m<2; m++ )
                            {
                                get_pred_mv_p( &tmp_mv, frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].ref,  8*i+m*4, 8*j+k*4, INTER4x4 );
#if TRACE
                                if ( 1 )
                                {
                                    if ( p_trace )
                                    {

                                        fprintf( p_trace, "tmp_mv:x,y of inter4x4 is: %i,%i \n\n", tmp_mv.x,tmp_mv.y );
                                    }
                                }
#endif

                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );

                                tmp_mv.ref=frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].ref;
                                frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m]=tmp_mv;

#if TRACE
                                if ( 1 )
                                {
                                    if ( p_trace )
                                    {

                                        fprintf( p_trace, "frm_mv:x,y of inter4x4 is: %i,%i \n\n", tmp_mv.x,tmp_mv.y );
                                    }
                                }
#endif
                            }

                    }
                    else
                    {
                        frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i]=intra_mv;
                        frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv = intra_mv;
                        frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv = intra_mv;
                    }
                }
                break;
        }
    }
    else
    {

        switch( currMB->mb_type )
        {
            case INTER16x16:
                switch( currMB->b8_ref[0][0] )
                {
                    case FW:
                        get_pred_mv_b( &tmp_mv,FW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=tmp_mv;
                        frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=intra_mv;
                        break;
                    case BW:
                        get_pred_mv_b( &tmp_mv,BW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=tmp_mv;
                        frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=intra_mv;
                        break;
                    case BI:
                        get_pred_mv_b( &tmp_mv,FW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].fw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].fw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].fw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].fw_mv=tmp_mv;

                        get_pred_mv_b( &tmp_mv,BW,0,0,INTER16x16 );

                        //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                        //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                        tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_16x16_QCODER );
                        tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_16x16_QCODER );

                        frm_bi_mv[img->block8_y][img->block8_x].bw_mv=
                            frm_bi_mv[img->block8_y][img->block8_x+1].bw_mv=
                                frm_bi_mv[img->block8_y+1][img->block8_x].bw_mv=
                                    frm_bi_mv[img->block8_y+1][img->block8_x+1].bw_mv=tmp_mv;
                        break;
                }
                break;

            case INTER8x8:
                for( block8x8=0; block8x8<4; block8x8++ )
                {
                    int j = block8x8/2;
                    int i = block8x8%2;
                    if ( currMB->subblock_type[block8x8]== SUBBLOCK_INTER8x8 )
                    {
                        switch( currMB->b8_ref[j][i] )
                        {
                            case FW:
                                get_pred_mv_b( &tmp_mv,FW,i*8,j*8,INTER8x8 );
                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv=tmp_mv;
                                frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv=intra_mv;
#if TRACE
                                if ( 1 )
                                {
                                    if ( p_trace )
                                    {

                                        fprintf( p_trace, "FW  tmp_mv_x  is: %i ,tmp_mv_y  is: %i \n\n", tmp_mv.x, tmp_mv.y );
                                    }
                                }
#endif
                                break;
                            case BW:
                                get_pred_mv_b( &tmp_mv,BW,i*8,j*8,INTER8x8 );

                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv=tmp_mv;
                                frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv=intra_mv;
#if TRACE
                                if ( 1 )
                                {
                                    if ( p_trace )
                                    {

                                        fprintf( p_trace, "BW  tmp_mv_x  is: %i ,tmp_mv_y  is: %i \n\n", tmp_mv.x, tmp_mv.y );
                                    }
                                }
#endif

                                break;
                            case BI:
                                get_pred_mv_b( &tmp_mv,FW,i*8,j*8,INTER8x8 );
                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv=tmp_mv;

                                get_pred_mv_b( &tmp_mv,BW,i*8,j*8,INTER8x8 );

                                //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_8x8_QCODER );
                                tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_8x8_QCODER );

                                frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv=tmp_mv;
                                break;
                        }
                    }
                    else if( currMB->subblock_type[block8x8]== SUBBLOCK_INTER4x4 )
                    {
                        int blk4x4;
                        for( blk4x4=0; blk4x4<4; blk4x4++ )
                        {
                            int k = blk4x4/2;
                            int m = blk4x4%2;
                            switch( currMB->b4_ref[block8x8][blk4x4] )
                            {
                                case FW:
                                    get_pred_mv_b( &tmp_mv,FW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );

                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv=tmp_mv;
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv=intra_mv;
                                    break;

                                case BW:
                                    get_pred_mv_b( &tmp_mv,BW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );

                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv=intra_mv;
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv=tmp_mv;
                                    break;

                                case BI:
                                    get_pred_mv_b( &tmp_mv,FW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv=tmp_mv;

                                    get_pred_mv_b( &tmp_mv,BW,( i*8+m*4 ),( j*8+k*4 ),INTER4x4 );
                                    //tmp_mv.x += qcoder_decode_mvdx(qcoder);
                                    //tmp_mv.y += qcoder_decode_mvdy(qcoder);
                                    tmp_mv.x += qcoder_decode_mvdx_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    tmp_mv.y += qcoder_decode_mvdy_num( qcoder,NUM_MVD_CX_4x4_QCODER );
                                    frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv=tmp_mv;
                                    break;

                            }
                        }
                    }
                    else
                    {
                        frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i]=intra_mv;
                        frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv = intra_mv;
                        frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv = intra_mv;

                    }
                }
                break;
        }
    }
}



void read_cbp_coeff( image_t *img, input_t *inp )
{
    int mb_nr = img->current_mb_nr;
    macroblock_t *currMB = &mb_data[mb_nr];
    int b8;

    currMB->qp = img->qp;

    for ( b8 = 0; b8 < 4; b8 ++ ) /* all modes */
    {
        read_luma_coeff_b8_qcoder( b8, inp, img );
    }
    read_chroma_coeff_b8_qcoder( 4, inp, img );
    read_chroma_coeff_b8_qcoder( 5, inp, img );
}

/*
*************************************************************************
* Function:decode one macroblock
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

int decode_one_macroblock( image_t *img, input_t *inp )
{
    int tmp_block[8][8], tmp_fw_block[8][8], tmp_bw_block[8][8];
    int i = 0, j = 0, ii = 0, jj = 0;
    int uv;
    int ioff, joff;
    int curr_blk[B8_SIZE][B8_SIZE];
    int curr_blk_16x16[MB_BLOCK_SIZE][MB_BLOCK_SIZE];
    int block8x8;
    int vec_x, vec_y;
    int k,m;
    int block4x4;
    int tmp_block_4x4[4][4], tmp_fw_block_4x4[4][4], tmp_bw_block_4x4[4][4];
    macroblock_t *currMB = &mb_data[img->current_mb_nr];
    int pred_dir;
    int bframe = ( img->type == B_IMG );
#if SYNTAX_REPORT
    int is_fwd = 0;
#endif

    // luma decoding
    for ( block8x8 = 0; block8x8 < 4; block8x8++ )
    {
        if ( currMB->mb_type!=I8MB && currMB->mb_type!=I4MB )
        {
            j=block8x8/2;
            i=block8x8%2;
            if( currMB->mb_type == INTER8x8 && currMB->subblock_type[block8x8] == SUBBLOCK_INTER4x4 )
            {
                for( block4x4=0; block4x4<4 ; block4x4++ )
                {
                    k=block4x4/2;
                    m=block4x4%2;
                    pred_dir = currMB->b4_ref[block8x8][block4x4];
                    if ( pred_dir != BI )
                    {
                        if ( !bframe )
                        {
#if QUARTER_PIXEL
                            vec_x = frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].x + ( ( img->block8_x+i )*32+m*16 );
                            vec_y = frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].y + ( ( img->block8_y+j )*32+k*16 );
#else
                            vec_x = frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].x + ( ( img->block8_x+i )*16+m*8 );
                            vec_y = frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].y + ( ( img->block8_y+j )*16+k*8 );
#endif

#if QUARTER_PIXEL
                            if ( vec_x > ( horizontal_size*4+32 ) || vec_x < -64 )
#else
                            if ( vec_x > ( horizontal_size*2+16 ) || vec_x < -32 )
#endif
                            {
                                CSyntax = 0;
#if SYNTAX_REPORT
                                is_fwd = 1;
                                fprintf( p_sreport,"error(4)       %s(Hor):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_x/4,block8x8,
                                         1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                            }
#if QUARTER_PIXEL
                            if ( vec_y > ( vertical_size*4+32 ) || vec_y < -64 )
#else

                            if ( vec_y > ( vertical_size*2+16 ) || vec_y < -32 )

#endif
                            {
                                CSyntax = 0;
#if SYNTAX_REPORT
                                fprintf( p_sreport,"error(4)       %s(Ver):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_y/4,block8x8,
                                         1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                            }
                            get_block_4x4( frm_mv_4x4[MAX_REF_NUM][img->block8_y+j][img->block8_x+i][k][m].ref, vec_x, vec_y, img, tmp_block_4x4 );

                        }
                        else      //  B frame single prediction
                        {
                            if( pred_dir == FW )
                            {
#if QUARTER_PIXEL
                                vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.x + ( ( img->block8_x+i )*32 + m*16 ); //dw 20110808
                                vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.y + ( ( img->block8_y+j )*32 + k*16 ); //dw 20110808
#else
                                vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.x + ( ( img->block8_x+i )*16+m*8 );
                                vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.y + ( ( img->block8_y+j )*16+k*8 );
#endif
                            }
                            else        //  BW
                            {
#if QUARTER_PIXEL
                                vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.x + ( ( img->block8_x+i )*32 + m*16 ); //dw 20110808
                                vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.y + ( ( img->block8_y+j )*32 + k*16 ); //dw 20110808
#else
                                vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.x + ( ( img->block8_x+i )*16+m*8 );
                                vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.y + ( ( img->block8_y+j )*16+k*8 );
#endif
                            }
#if QUARTER_PIXEL
                            if ( vec_x > ( horizontal_size*4+32 ) || vec_x < -64 )
                                if ( vec_x > ( horizontal_size*2+16 ) || vec_x < -32 )
#endif
                                {
                                    CSyntax = 0;
#if SYNTAX_REPORT
                                    fprintf( p_sreport,"error(4)       %s(Hor):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_x/4,block8x8,
                                             1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                                }
#if QUARTER_PIXEL
                            if ( vec_y > ( vertical_size*4+32 ) || vec_y < -64 ) //BUG Fixed
#else

                            if ( vec_y > ( vertical_size*2+16 ) || vec_y < -32 )

#endif
                            {
                                CSyntax = 0;
#if SYNTAX_REPORT
                                fprintf( p_sreport,"error(4)       %s(Ver):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_y/4,block8x8,
                                         1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                            }
                            get_block_4x4( pred_dir, vec_x, vec_y, img, tmp_block_4x4 );
                        }
                        for ( ii = 0; ii < 4; ii++ )
                            for ( jj = 0; jj < 4; jj++ )
                                img->mpr[ii + i*8 +m*4][jj + j*8 + k*4] = tmp_block_4x4[ii][jj];
                    }
                    else    //  B frame Bi direction
                    {
#if QUARTER_PIXEL
                        vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.x + ( ( img->block8_x+i )*32 + m*16 ); //dw 20110808
                        vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.y + ( ( img->block8_y+j )*32 + k*16 ); //dw 20110808
#else
                        vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.x + ( ( img->block8_x+i )*16+m*8 );
                        vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].fw_mv.y + ( ( img->block8_y+j )*16+k*8 );
#endif
                        //  check range TODO
                        get_block_4x4( FW, vec_x, vec_y, img, tmp_fw_block_4x4 );

#if QUARTER_PIXEL
                        vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.x + ( ( img->block8_x+i )*32 + m*16 ); //dw 20110808
                        vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.y + ( ( img->block8_y+j )*32 + k*16 ); //dw 20110808
#else
                        vec_x = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.x + ( ( img->block8_x+i )*16+m*8 );
                        vec_y = frm_bi_mv_4x4[img->block8_y+j][img->block8_x+i][k][m].bw_mv.y + ( ( img->block8_y+j )*16+k*8 );
#endif
                        //  check range TODO
                        get_block_4x4( BW, vec_x, vec_y, img, tmp_bw_block_4x4 );
                        for ( ii = 0; ii < 4; ii++ )
                            for ( jj = 0; jj < 4; jj++ )
                                img->mpr[ii + i*8 +m*4][jj + j*8 + k*4]  = ( tmp_fw_block_4x4[ii][jj]+tmp_bw_block_4x4[ii][jj]+1 )>>1;
                    }
                }
            }
            else if( currMB->mb_type == INTER8x8 && ( currMB->subblock_type[block8x8] == SUBBLOCK_INTRA4x4 || currMB->subblock_type[block8x8] == SUBBLOCK_INTRA8x8 ) )
            {
                ioff = i * 8;
                joff = j * 8;
                for ( ii = 0; ii < 8; ii++ )
                    for ( jj = 0; jj < 8; jj++ )
                        img->mpr[ii + ioff][jj + joff] = 128;
            }
            else
            {
                ioff = i * 8;
                joff = j * 8;
                pred_dir = currMB->b8_ref[j][i];

                if ( pred_dir != BI )
                {
                    //===== FORWARD/BACKWARD PREDICTION =====

                    if ( !bframe )
                    {
#if QUARTER_PIXEL
                        vec_x = frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].x + ( img->block8_x+i )*32; //dw 20110808
                        vec_y = frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].y + ( img->block8_y+j )*32; //dw 20110808
#else
                        vec_x = frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].x + ( img->block8_x+i )*16;
                        vec_y = frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].y + ( img->block8_y+j )*16;
#endif
#if QUARTER_PIXEL
                        if ( vec_x > ( horizontal_size*4+32 ) || vec_x < -64 )
#else
                        if ( vec_x > ( horizontal_size*2+16 ) || vec_x < -32 )
#endif
                        {
                            CSyntax = 0;
#if SYNTAX_REPORT
                            is_fwd = 1;
                            fprintf( p_sreport,"error(4)       %s(Hor):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_x/4,block8x8,
                                     1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                        }
#if QUARTER_PIXEL
                        if ( vec_y > ( vertical_size*4+32 ) || vec_y < -64 ) //BUG Fixed
#else

                        if ( vec_y > ( vertical_size*2+16 ) || vec_y < -32 )

#endif
                        {
                            CSyntax = 0;
#if SYNTAX_REPORT
                            fprintf( p_sreport,"error(4)       %s(Ver):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_y/4,block8x8,
                                     1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                        }
                        get_block( frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i].ref, vec_x, vec_y, img, tmp_block );

                    }
                    else      //  B frame single prediction
                    {
                        if( pred_dir == FW )
                        {
#if QUARTER_PIXEL
                            vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.x + ( img->block8_x+i )*32;
                            vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.y + ( img->block8_y+j )*32;
#else
                            vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.x + ( img->block8_x+i )*16;
                            vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.y + ( img->block8_y+j )*16;
#endif
                        }
                        else        //  BW
                        {
#if QUARTER_PIXEL
                            vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.x + ( img->block8_x+i )*32; //dw 20110808
                            vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.y + ( img->block8_y+j )*32; //dw 20110808
#else
                            vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.x + ( img->block8_x+i )*16;
                            vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.y + ( img->block8_y+j )*16;
#endif
                        }
#if QUARTER_PIXEL
                        if ( vec_x > ( horizontal_size*4+32 ) || vec_x < -64 ) //dw 20110808
#else
                        if ( vec_x > ( horizontal_size*2+16 ) || vec_x < -32 )
#endif
                        {
                            CSyntax = 0;
#if SYNTAX_REPORT
                            fprintf( p_sreport,"error(4)       %s(Hor):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_x/4,block8x8,
                                     1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                        }
#if QUARTER_PIXEL
                        if ( vec_y > ( vertical_size*4+32 ) || vec_y < -64 ) //BUG Fixed
#else

                        if ( vec_y > ( vertical_size*2+16 ) || vec_y < -32 )

#endif
                        {
                            CSyntax = 0;
#if SYNTAX_REPORT
                            fprintf( p_sreport,"error(4)       %s(Ver):(%5d) @ Blk%d MB%d\n", is_fwd==1?"Fwd":"Bwd", vec_y/4,block8x8,
                                     1 /*img->picture_structure*/==0?img->current_mb_nr_fld:img->current_mb_nr );
#endif
                        }


                        get_block( pred_dir, vec_x, vec_y, img, tmp_block );
                    }
                    for ( ii = 0; ii < 8; ii++ )
                        for ( jj = 0; jj < 8; jj++ )
                            img->mpr[ii + ioff][jj + joff] = tmp_block[ii][jj];
                }
                else    //  B frame Bi direction
                {
#if QUARTER_PIXEL
                    vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.x + ( img->block8_x+i )*32; //dw 20110808
                    vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.y + ( img->block8_y+j )*32; //dw 20110808
#else
                    vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.x + ( img->block8_x+i )*16;
                    vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].fw_mv.y + ( img->block8_y+j )*16;
#endif

                    get_block( FW, vec_x, vec_y, img, tmp_fw_block );

#if QUARTER_PIXEL
                    vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.x + ( img->block8_x+i )*32; //dw 20110808
                    vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.y + ( img->block8_y+j )*32; //dw 20110808
#else
                    vec_x = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.x + ( img->block8_x+i )*16;
                    vec_y = frm_bi_mv[img->block8_y+j][img->block8_x+i].bw_mv.y + ( img->block8_y+j )*16;
#endif

                    get_block( BW, vec_x, vec_y, img, tmp_bw_block );
                    for ( ii = 0; ii < 8; ii++ )
                        for ( jj = 0; jj < 8; jj++ )
                            img->mpr[ii + ioff][jj + joff] = ( tmp_fw_block[ii][jj]+tmp_bw_block[ii][jj]+1 )>>1;
                }
            }
        }

        //  for intra
        if( currMB->mb_type==I8MB )
            for ( ii = 0; ii < 16; ii++ )
                for ( jj = 0; jj < 16; jj++ )
                    img->mpr[ii ][jj ] = 128;
        //
        //  for skip
        if( IS_COPY( currMB ) )
        {
            for ( ii = 0; ii < 16; ii++ )
                for ( jj = 0; jj < 16; jj++ )
                {
                    img->m7[ii][jj]=0;
                }
        }
        //

        get_curr_blk( block8x8, img, curr_blk );

        if ( vbs_enable )
        {
            if ( currMB->transform_16x16==0 )    //  not 16x16
            {
                if ( currMB->transform_4x4[block8x8]==1 ) //  4x4
                {
                    idct_dequant_B8inB4( block8x8, currMB->qp - MIN_QP, curr_blk, img );
                }
                else
                {
                    idct_dequant_B8( block8x8, currMB->qp - MIN_QP, curr_blk, img );
                }

            }
        }
        else
        {
            if ( currMB->mb_type==I8MB )
            {
                idct_dequant_B8( block8x8, currMB->qp - MIN_QP, curr_blk, img );
            }
            else
            {
                idct_dequant_B8( block8x8, currMB->qp - MIN_QP, curr_blk, img );
                //No Intra Prediction
            }
        }
    }


    //  16x16
    if ( vbs_enable )
    {
        if ( currMB->transform_16x16==1 )
        {
            get_curr_blk_16x16( img,curr_blk_16x16 );
            inv_transform_B16( curr_blk_16x16 );
            for ( jj = 0; jj < 16; jj++ )
                for ( ii = 0; ii < 16; ii++ )
                {
                    p_img_y_dec[img->pix_y +jj][img->pix_x +ii]= RFM_CLIP3( ( img->mpr[ii][jj] + curr_blk_16x16[jj][ii] ),0,255 );
                }
        }
    }

    if ( chroma_format == 1 )
    {
        for ( uv = 0; uv < 2; uv++ )
        {
            pred_dir = currMB->b8_ref[j][i];   //  for P
            // PREDICTION
            if ( currMB->mb_type == I8MB )
            {
            }
            else if ( pred_dir != BI )
            {
                //--- FORWARD/BACKWARD PREDICTION ---
                if ( !bframe )
                {
                    get_block_uv( currMB,uv );

                }
                else
                {
                    get_block_uv( currMB,uv );
                }
            }
            else                  // !! bidirection prediction
            {
                get_block_uv( currMB,uv );
            }

            get_curr_blk( 4 + uv, img, curr_blk );

            idct_dequant_B8( 4 + uv, QP_SCALE_CR[currMB->qp - MIN_QP], curr_blk, img );
        }
    }
    return 0;
}
